package cn.apotato.security.aspect;

import cn.apotato.security.annotation.RequiresLogin;
import cn.apotato.security.annotation.RequiresPermissions;
import cn.apotato.security.annotation.RequiresRoles;
import cn.apotato.security.auth.AuthUtil;
import lombok.AllArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 基于 Aop 的注解鉴权
 *
 * @author 胡晓鹏
 * @date 2023/05/30
 */
@AllArgsConstructor
@Aspect
@Component
public class PreAuthorizeAspect {

    /**
     * 定义AOP签名 (切入所有使用鉴权注解的方法)
     */
    public static final String POINTCUT_SIGN = " @annotation(cn.apotato.security.annotation.RequiresLogin) || "
            + "@annotation(cn.apotato.security.annotation.RequiresPermissions) || "
            + "@annotation(cn.apotato.security.annotation.RequiresRoles)";

    /**
     * 设置切入点
     */
    @Pointcut(POINTCUT_SIGN)
    public void pointcut() {
    }

    /**
     * 环绕切入
     *
     * @param point 切面对象
     * @return {@link Object}
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 注解鉴权
        MethodSignature signature = (MethodSignature) point.getSignature();
        checkMethodAnnotation(signature.getMethod());
        return point.proceed();
    }

    /**
     * 检查方法注释
     *
     * @param method 方法
     */
    private void checkMethodAnnotation(Method method) {
        // 校验 @RequiresLogin 注解
        RequiresLogin requiresLogin = method.getAnnotation(RequiresLogin.class);
        if (requiresLogin != null) {
            AuthUtil.checkLogin();
        }
        // 校验 @RequiresRoles 注解
        RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class);
        if (requiresRoles != null) {
            AuthUtil.checkRole(requiresRoles);
        }

        // 校验 @RequiresPermissions 注解
        RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
        if (requiresPermissions != null) {
            AuthUtil.checkPermi(requiresPermissions);
        }
    }

}
